package com.huisenky.smallidea.diff.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.huisenky.smallidea.common.util.BeeUtils;
import com.huisenky.smallidea.diff.annotation.SmallDiff;
import com.huisenky.smallidea.diff.comment.DiffComment;
import com.huisenky.smallidea.diff.constants.SmallFieldConstant;

import javax.annotation.Nonnull;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.function.Predicate;

public class DiffUtil {

    private DiffUtil() {
    }

    /*
        使用
     */
    public static <T> String compare( T newObj, Object oldObj, DiffComment diffComment) {
        Class<? extends Annotation> annotation = ClassUtil.loadClass(diffComment.getAnnotation());
        return compare2Str(newObj,oldObj,oldField -> true, annotation, diffComment.getAnnotationMethod(), diffComment.getIgnoreProperties());

    }


        /**
         * smallDiff 定义格式   ApiModelProperty 定义注解值
         * BeDiff.compare2Str(newDO, oldDO, ApiModelProperty.class, "value");
         */
    public static <T> String compare2Str(T newObj, T oldObj, @Nonnull Class<? extends Annotation> annotation, @Nonnull String annotationMethod, String... ignoreProperties) {
        return compare2Str(newObj, oldObj, oldField -> true, annotation, annotationMethod, ignoreProperties);
    }

    /**
     *   用法：      String diffStr = BeDiff.compare2Str(newObj, oldObj, ObjectUtil::isNotNull, ApiModelProperty.class, "value", ignoreCompare);
     */
    public static <T> String compare2Str(T newObj, T oldObj, Predicate<Object> oldFilter, @Nonnull Class<? extends Annotation> annotation, @Nonnull String annotationMethod, String... ignoreProperties) {
        if (newObj == null) {
            return "";
        }
        Field[] fields = ReflectUtil.getFields(newObj.getClass());
        SmallDiff smallDiff = newObj.getClass().getAnnotation(SmallDiff.class);
        String format = getFormat(smallDiff);

        StringBuilder messageBuilder = new StringBuilder();
        if (checkFormat(format)) {
            for (Field newField : fields) {
                if (CollUtil.toList(ignoreProperties).contains(newField.getName())) {
                    continue;
                }
                Object newFieldVal = ReflectUtil.getFieldValue(newObj, newField);
                // newFieldVal为null，说明该字段没有修改
                if (newFieldVal != null) {
                    Object oldFieldVal = ReflectUtil.getFieldValue(oldObj, newField.getName());
                    if (oldFilter.test(oldFieldVal)) {
                        Annotation commentAnnotation = newField.getAnnotation(annotation);
                        String annotationComment = BeeUtils.getAnnotationComment(commentAnnotation, annotationMethod);
                        String comment = StrUtil.isNotBlank(annotationComment) ? annotationComment : newField.getName();
                        if (oldFieldVal == null) {
                            messageBuilder.append(buildMessage(format, comment, "", BeeUtils.defaultValStr(newFieldVal),newField.getName()));
                        } else if (!oldFieldVal.equals(newFieldVal)) {
                            //判断 BigDecimal
                            if (specialOptimize(oldFieldVal, newFieldVal)) {
                                messageBuilder.append(buildMessage(format, comment, BeeUtils.defaultValStr(oldFieldVal), BeeUtils.defaultValStr(newFieldVal),newField.getName()));
                            }
                        }
                    }
                }
            }
        }
        return messageBuilder.toString();
    }

    private static boolean specialOptimize(Object oldVal, Object newVal) {
        if (oldVal instanceof BigDecimal) {
            return ((BigDecimal) oldVal).compareTo((BigDecimal) newVal) != 0;
        }
        return true;
    }

    private static String getFormat(SmallDiff smallDiff) {
        if (smallDiff == null) {
            //获取class的默认值
            Class<SmallDiff> smallDiffClass = SmallDiff.class;
            Method[] methods = smallDiffClass.getMethods();
            String defaultValue = (String) methods[0].getDefaultValue();
            return defaultValue;
//            return SmallFieldConstant.FIELD + "字段: " + SmallFieldConstant.Diff.OLD + " , 修改为: " + SmallFieldConstant.Diff.NEW + "; ";
        } else {
            return smallDiff.value();
        }
    }

    private static boolean checkFormat(String format) {
        return format.contains(SmallFieldConstant.FIELD);
    }

    private static String buildMessage(String format, String fieldDesc, String oldVal, String newVal, String fieldName) {
        return format.replace(SmallFieldConstant.FIELD, fieldDesc)
                .replace(SmallFieldConstant.Diff.OLD, oldVal)
                .replace(SmallFieldConstant.Diff.NEW, newVal)
                .replace(SmallFieldConstant.KEY,fieldName);
    }
}
